/**
* AutoSWF - Cody Cushing. March 26, 2009
* Copyright (c) 2009 Cody Cushing
* No use restrictions. Maintain this notice in all versions. 
**/

package com.autoswf.taskrunner
{
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	/**
	 * Allows primary and secondary task queuing/execution.
	 * 
	 * Class is alpha - not tested in a project
	 */
	public class TaskController extends EventDispatcher
	{
		protected var taskModel:TaskModel;
		
		protected var completeTasks:Dictionary;
		protected var primaryTasks:Array;
		protected var secondaryTasks:Array;
		

		protected var totalConcurrentTasks:int = 0;
		
		
		protected var _allowedConcurrentTasks:int = 2;
		
		public function get allowedConcurrentTasks():int
		{
			return _allowedConcurrentTasks;
		}
		public function set allowedConcurrentTasks(value:int):void
		{
			_allowedConcurrentTasks = value;
		}
		

		
		
		/**
		 * Constructor.
		 */		
		public function TaskController(taskModel:TaskModel)
		{
			this.taskModel = taskModel;
			this.taskModel.addEventListener(TaskEvent.TASK_COMPLETE, taskModel_completeHandler);
			this.taskModel.addEventListener(TaskEvent.TASK_FAILURE, taskModel_errorHandler);
			
			completeTasks = new Dictionary();
			primaryTasks = [];
			secondaryTasks = [];
		}
		
		
		public function data(id:String):*
		{
			return taskModel.result(id);
		}
		
		
		/** Run first. */
		public function addPrimary(request:IRequest):void
		{
			primaryTasks.push(request);
		}
		
		
		/** Run after primary tasks complete. */
		public function addBackground(request:IRequest):void
		{
			secondaryTasks.push(request);
		}
		
		
		/** Begin running primary and secondary tasks. */		
		public function runTasks():void
		{
			if(checkPrimaryComplete()) /* Notify if primary tasks are complete */
			{
				checkSecondaryComplete(); /* Notify if secondary tasks are complete */
			}
			
			while(totalConcurrentTasks < _allowedConcurrentTasks && hasNext())
			{
				totalConcurrentTasks++;
				runNext();
			}
		}
		
		
		protected function taskModel_completeHandler(event:TaskEvent):void
		{
			totalConcurrentTasks--;
			if(hasNext())
			{
				runNext();
			}
		}
		
		
		protected function taskModel_errorHandler(event:TaskEvent):void
		{
			totalConcurrentTasks--;
			if(hasNext())
			{
				runNext();
			}
		}
		
		
		protected function hasNext():Boolean
		{
			return (primaryTasks.length || secondaryTasks.length);
		}
		
		
		protected function runNext():void
		{
			if(primaryTasks.length)
			{
				taskModel.addTask(primaryTasks.pop());
				checkPrimaryComplete();
				return;
			}
			if(secondaryTasks.length)
			{
				taskModel.addTask(secondaryTasks.pop());
				checkSecondaryComplete();
				return;
			}
		}
		
		
		protected function checkPrimaryComplete():Boolean
		{
			if(primaryTasks.length == 0)
			{
				dispatchEvent(new TaskEvent(TaskEvent.PRIMARY_TASK_COMPLETE, null));
			}
			return (primaryTasks.length == 0)
		}
		
		
		protected function checkSecondaryComplete():void
		{
			if(secondaryTasks.length == 0)
			{
				dispatchEvent(new TaskEvent(TaskEvent.SECONDARY_TASK_COMPLETE, null));
			}
		}

	}
}